package de.fh.ffm.elevator;

/**
 * Floor in a building having access to an elevator
 * 
 * @author harscher <swe.chr@googlemail.com>
 * 
 */
public class Floor {

	/**
	 * Doors of the floor
	 * 
	 * @author mann <mann.mario@googlemail.com>
	 */
	private static class FloorDoor extends Door {

		/**
		 * The floor this Door is at
		 */
		private final Floor floor;

		/**
		 * Creates a FloorDoor with the corresponding Floor
		 * 
		 * @param floor
		 *            , the Floor this Door is at
		 */
		public FloorDoor ( final Floor floor ) {
			this.floor = floor;
		}

		/**
		 * check if the elevator doors can be opened
		 * 
		 * @return true if an elevator is present; false otherwise;
		 */
		public boolean canBeOpened () {
			return floor.isElevatorPresent();
		}

	}

	/**
	 * Button of the Floor
	 * 
	 * @author claudio
	 * 
	 */
	private static class FloorButton extends Button {

		private final Floor floor;

		/**
		 * Creates a FloorButton with corresponding Floor
		 * 
		 * @param floor
		 *            the Floor this FloorButton is at
		 */
		public FloorButton ( final Floor floor ) {
			this.floor = floor;
		}

		@Override
		/**
		 * This static method is automatically called by pushing an Button via push().
		 * In this case, pushing the FloorButton calls an Elevator to the Floor this Button belongs to. 
		 */
		public void onPush () {
			getElevatorManager().callElevatorToFloor(floor);
		}
	}

	/**
	 * Is thrown when someone tries to enter or exit this floor when its door is
	 * closed
	 * 
	 * @author mann <mann.mario@googlemail.com>
	 */
	static class DoorClosedException extends RuntimeException {
		private static final long serialVersionUID = 1L;
	}

	/**
	 * Is thrown when a Person tries to enter a full floor
	 * 
	 * @author Frank
	 */
	public static class IsFullException extends RuntimeException {
		private static final long serialVersionUID = 1L;
	}

	/**
	 * if null, no elevator is present
	 */
	private Elevator elevator;

	/**
	 * button used to call the elevator
	 */
	private Button button = new FloorButton(this);

	/**
	 * door on the floor in front of the elevator
	 */
	private Door door = new FloorDoor(this);

	/**
	 * A person located on this Floor
	 * 
	 * person = null means nobody is present
	 */
	private Person person;

	/**
	 * get the door of the floor
	 * 
	 * @return the door
	 */
	public Door getDoor () {
		return door;
	}

	/**
	 * check if an elevator is present on the floor
	 * 
	 * @return true if an elevator is on this floor; false otherwise;
	 */
	public boolean isElevatorPresent () {
		return null != elevator;
	}

	/**
	 * set an arrived elevator
	 * 
	 * @param elevator
	 */
	public void elevatorArrived ( Elevator elevator ) {
		this.elevator = elevator;
	}

	/**
	 * unset a leaving elevator
	 * 
	 * @param elevator
	 */
	public void elevatorLeft ( Elevator elevator ) {
		this.elevator = null;
	}

	/**
	 * @return The FloorButton belonging to this Floor.
	 */
	public Button getButton () {
		// TODO Auto-generated method stub
		return button;
	}

	/**
	 * check if a Person can exit the elevator to this Floor
	 * 
	 * @return true if one Person can exit; false otherwise;
	 */
	public boolean canPersonEnter () {
		return null == person;
	}

	/**
	 * Returns the Person located at this Floor.
	 * 
	 * @return the Person located at this Floor
	 */
	public Person getPerson () {
		return person;
	}

	/**
	 * Put a Person on this Floor.
	 * 
	 * @throws IsFullException
	 *             if someone is already present
	 * 
	 * @param p
	 *            the Person to be put on this Floor
	 */
	public void setPerson ( Person p ) {
		if ( null == p ) {
			person = null;
		} else {
			if ( null != person ) {
				throw new IsFullException();
			}

			person = p;

			if ( this != p.getFloor() ) {
				p.setFloor(this);
			}
		}
	}

}
